﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace Sharp.UI.Forms
{
    using Compiler.CSharp;
    using IO;
    public partial class MainForm : Form
    {
        IO.File SourceCodeFile = new IO.File();
        Lexicon Lex  = new Lexicon();
        // Text Highlighting Colors
        Color ColorPunctuators = Color.DarkMagenta;
        Color ColorLiterals = Color.DarkOrange;
        Color ColorKeywords = Color.Blue;
        Color ColorComments = Color.Green;
        Color ColorOperators = Color.Indigo;
        Color ColorIdentifiers = Color.DarkCyan;
        Color ColorPreProcessorDirectives = Color.Brown;
        Color ColorErrors = Color.Red;
        Color ColorUnsupported = Color.LightGray;
        int CharacterPosition;
        public MainForm()
        {
            InitializeComponent();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "C# files (*.cs)|*.cs|All files (*.*)|*.*";
            double TimeOpenFile;
            // Get C# file
            DialogResult dr = ofd.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                // open file
                SourceCodeFile = new IO.File();
                Lex = new Lexicon();
                DateTime start = DateTime.Now;
                SourceCodeFile.Open(ofd.FileName);
                TimeSpan timeDiff = DateTime.Now - start;
                TimeOpenFile = timeDiff.TotalMilliseconds;
                // Fill text area
                SourceCode.Text = SourceCodeFile.Text;
            }
            else
            {
                return;
            }
            if (SourceCodeFile.Text != "")
            {
                ResetAnalysisHighlighter();
                toolStripStatusLabel.Text = "Stage: Transformation. Converting to Unicode.";
                toolStripProgressBar.Value = 1;
                // C# already converts the file into unicode-16
                toolStripStatusLabel.Text = "Stage: Lexical Analysis. ";
                Lex = new Lexicon();
                DateTime start = DateTime.Now;
                Lex.Analyse(SourceCodeFile.Text);
                TimeSpan timeDiff = DateTime.Now - start;

                PerformanceTable.Items.Clear();
                ListViewItem ListItem;

                Process proc = Process.GetCurrentProcess();

                ListItem = new ListViewItem();
                ListItem.Text = "Processor";
                ListItem.SubItems.Add(
                    System.Environment.GetEnvironmentVariable(
                    "PROCESSOR_IDENTIFIER"));
                ListItem.SubItems.Add("-");
                PerformanceTable.Items.Add(ListItem);


                ListItem = new ListViewItem();
                ListItem.Text = "Architecture";
                ListItem.SubItems.Add(
                    System.Environment.GetEnvironmentVariable(
                    "PROCESSOR_ARCHITECTURE"));
                ListItem.SubItems.Add("-");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Cores/CPUs";
                ListItem.SubItems.Add(
                    System.Environment.GetEnvironmentVariable(
                    "NUMBER_OF_PROCESSORS"));
                ListItem.SubItems.Add("-");
                PerformanceTable.Items.Add(ListItem);
                
                ListItem = new ListViewItem();
                ListItem.Text = "Working Set Memory";
                ListItem.SubItems.Add(
                    proc.WorkingSet64.ToString());
                ListItem.SubItems.Add("Bytes");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Private Memory";
                ListItem.SubItems.Add(
                    proc.PrivateMemorySize64.ToString());
                ListItem.SubItems.Add("Bytes");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Threads";
                ListItem.SubItems.Add(
                    proc.Threads.Count.ToString());
                ListItem.SubItems.Add("Bytes");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Lines of code";
                ListItem.SubItems.Add(SourceCodeFile.TotalSourceLines + " Lines");
                ListItem.SubItems.Add("-");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Time taken to open source file";
                if (TimeOpenFile <= 0)
                {
                    ListItem.SubItems.Add("< 1 Millisecond (ms)");
                }
                else
                {
                    ListItem.SubItems.Add(TimeOpenFile.ToString() + " Milliseconds (ms)");
                }
                ListItem.SubItems.Add("-");
                PerformanceTable.Items.Add(ListItem);

                ListItem = new ListViewItem();
                ListItem.Text = "Time taken to complete lexicon analysis";
                double result = timeDiff.TotalMilliseconds;
                if (result <= 0)
                {
                    ListItem.SubItems.Add("< 1 Millisecond (ms)");
                }
                else
                {
                    ListItem.SubItems.Add(result.ToString() + " Milliseconds (ms)");
                }
                ListItem.SubItems.Add("<= 200 ms");    
                PerformanceTable.Items.Add(ListItem);

                PopulateLexiconBoundaryTable();
                ListItem = new ListViewItem();
                ListItem.Text = "Lexicon Boundary Points";
                ListItem.SubItems.Add(
                    LBPTable.Items.Count.ToString());
                ListItem.SubItems.Add("LBPs");
                PerformanceTable.Items.Add(ListItem);

                PerformanceTable.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

                SourceCode.Enabled = true;
                ShowAnalysisHighlighter();
                
                toolStripProgressBar.Value = 100;
                toolStripStatusLabel.Text = SourceCodeFile.Name;
            }
        }
        private void PopulateLexiconBoundaryTable()
        {
            LBPTable.Items.Clear();
            foreach (LexiconBoundaryPoint LBP in Lex.LBP)
            {
                ListViewItem ListItem = new ListViewItem();
                // Text highlighting
                if (Lex.WhatTypeIs(LBP.Type) == "Keyword")
                {
                    ListItem.ForeColor = ColorKeywords;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Identifier")
                {
                    ListItem.ForeColor = ColorIdentifiers;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Literal")
                {
                    ListItem.ForeColor = ColorLiterals;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Punctuator")
                {
                    ListItem.ForeColor = ColorPunctuators;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Operator")
                {
                    ListItem.ForeColor = ColorOperators;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Comment")
                {
                    ListItem.ForeColor = ColorComments;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "PreProcessorDirective")
                {
                    ListItem.ForeColor = ColorPreProcessorDirectives;
                }
                // Errors and unsupported features
                if (Lex.WhatTypeIs(LBP.Type) == "Error" ||
                    Lex.WhatTypeIs(LBP.SubType) == "Error")
                {
                    ListItem.ForeColor = ColorErrors;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Unsupported" ||
                        Lex.WhatTypeIs(LBP.SubType) == "Unsupported")
                {
                    ListItem.ForeColor = ColorUnsupported;
                }
                ListItem.Text = LBP.Start.ToString() + " " + 
                    SourceCodeFile.Text[LBP.Start] +" ";
                ListItem.SubItems.Add(LBP.End.ToString()+ " " + 
                    SourceCodeFile.Text[LBP.End] +"");
                ListItem.SubItems.Add(LBP.Type.ToString() + " (" +
                                       Lex.WhatTypeIs(LBP.Type) + ")");
                ListItem.SubItems.Add(LBP.SubType.ToString() + " (" +
                                       Lex.WhatTypeIs(LBP.SubType) + ")");
                LBPTable.Items.Add(ListItem);
            }
            LBPTable.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }
        private void ShowAnalysisHighlighter()
        {
            if (!highlightingToolStripMenuItem.Checked)
            {
                return;
            }
            int selection = SourceCode.SelectionStart;
            int selectionStart = 0;
            int selectionLength = 1;
            foreach (LexiconBoundaryPoint LBP in Lex.LBP)
            {
                // Fix Selection
                selectionStart = LBP.Start;
                selectionLength = (LBP.End - LBP.Start) + 1;
                //
                if (Lex.WhatTypeIs(LBP.Type) == "Keyword")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorKeywords;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Identifier")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorIdentifiers;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Literal")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorLiterals;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Punctuator")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorPunctuators;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Operator")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorOperators;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "Comment")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorComments;
                }
                else if (Lex.WhatTypeIs(LBP.Type) == "PreProcessorDirective")
                {
                    SourceCode.Select(selectionStart, selectionLength);
                    SourceCode.SelectionColor = ColorPreProcessorDirectives;
                }
            }
            SourceCode.Select(selection, 0);
        }
        private void ResetAnalysisHighlighter()
        {
            int selection = SourceCode.SelectionStart;
            SourceCode.SelectAll();
            SourceCode.SelectionColor = Color.Black;
            SourceCode.Select(selection, 0);
        }

        private void readOnlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SourceCode.ReadOnly = readOnlyToolStripMenuItem.Checked;
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            
        }

        private void toolStripProgressBar_Paint(object sender, PaintEventArgs e)
        {
            toolStripStatusLabelProgress.Text = "Progress: " + 
                toolStripProgressBar.Value.ToString() + "%";
        }

        private void highlightingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (highlightingToolStripMenuItem.Checked)
            {
                ShowAnalysisHighlighter();
            }
            else
            {
                ResetAnalysisHighlighter();
            }
        }

        private void saveReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog SFD = new FolderBrowserDialog();
            //SFD.Filter = "Compessed Folder (*.zip)|*.zip";
            String FolderName = "Sharp(" +
                DateTime.Now.Hour.ToString() + "." +
                DateTime.Now.Minute.ToString() + "." +
                DateTime.Now.Second.ToString() +
                ")(" +
                DateTime.Now.Day.ToString() + "." +
                DateTime.Now.Month.ToString() + "." +
                DateTime.Now.Year.ToString();
            FolderName += ")";
            //SFD.FileName = fileName;
            if (SFD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                IO.File PerfomanceFile = new File();
                IO.File LBPFile = new File();
                string FileLine = "";
                #region PerfomanceFile
                // CSV file format
                // file headers
                for (int i = 0; i < PerformanceTable.Columns.Count; i++)
                {
                    FileLine += PerformanceTable.Columns[i].Text;
                    if (i < PerformanceTable.Columns.Count - 1)
                    {
                        FileLine += "\r";
                    }
                    else
                    {
                        FileLine += "\n";
                    }
                }
                // Items
                for (int i = 0; i < PerformanceTable.Items.Count; i++)
                {
                    ListViewItem LVI = PerformanceTable.Items[i];

                    for (int ii = 0; ii < LVI.SubItems.Count; ii++)
                    {
                        FileLine += LVI.SubItems[ii].Text;
                        //FileLine += ",";
                        if (ii < LVI.SubItems.Count - 1)
                        {
                            FileLine += "\r";
                        }    
                    }
                    FileLine += "\n";
                }
                PerfomanceFile.Text = FileLine;
                #endregion
                #region LBPFile
                // CSV file format
                // file headers
                FileLine = "";
                for (int i = 0; i < LBPTable.Columns.Count; i++)
                {
                    FileLine += LBPTable.Columns[i].Text;
                    if (i < LBPTable.Columns.Count - 1)
                    {
                        FileLine += "\r";
                    }
                    else
                    {
                        FileLine += "\n";
                    }
                }
                // Items
                for (int i = 0; i < LBPTable.Items.Count; i++)
                {
                    ListViewItem LVI = LBPTable.Items[i];

                    for (int ii = 0; ii < LVI.SubItems.Count; ii++)
                    {
                        FileLine += LVI.SubItems[ii].Text;
                        //FileLine += ",";
                        if (ii < LVI.SubItems.Count - 1)
                        {
                            FileLine += "\r";
                        }
                    }
                    FileLine += "\n";
                }
                LBPFile.Text = FileLine;
                #endregion
                #region SaveFiles
                string url =  SFD.SelectedPath +"\\" + FolderName + "\\";
                System.IO.Directory.CreateDirectory(url);
                SourceCodeFile.Save(url + "SourceCodeFile.txt");
                PerfomanceFile.Save(url + "PerfomanceFile.csv");
                LBPFile.Save(url + "LBPFile.csv");
                #endregion
            }
        }

        private void openReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog SFD = new FolderBrowserDialog();
            //SFD.Filter = "Compessed Folder (*.zip)|*.zip";
            //SFD.FileName = fileName;
            if (SFD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string path = SFD.SelectedPath.ToString();
                string urlSourceCode = path + "\\" + "SourceCodeFile.txt";
                string urlPerfomanceFile = path + "\\" + "PerfomanceFile.csv";
                string urlLBPFile = path + "\\" + "LBPFile.csv";
                
                if (SourceCodeFile.Exists(urlSourceCode))
                {
                    SourceCodeFile.Open(urlSourceCode);
                    SourceCode.Text = SourceCodeFile.Text;
                }
                else
                {
                    MessageBox.Show("Missing: " + System.IO.Path.GetFileName(urlSourceCode), "Error", 
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                IO.File PerfomanceFile = new File();
                if (SourceCodeFile.Exists(urlPerfomanceFile))
                {
                    PerfomanceFile.Open(urlPerfomanceFile);
                }
                else
                {
                    MessageBox.Show("Missing: " + System.IO.Path.GetFileName(urlPerfomanceFile), "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                IO.File LBPFile = new File();
                if (SourceCodeFile.Exists(urlLBPFile))
                {
                    LBPFile.Open(urlLBPFile);
                    
                }
                else
                {
                    MessageBox.Show("Missing: " + System.IO.Path.GetFileName(urlLBPFile), "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                #region PerfomanceFile
                if (PerfomanceFile.Text != "")
                {
                    PerformanceTable.Clear();
                    List<LexiconBoundaryPoint> lbp = new List<LexiconBoundaryPoint>();
                    LexiconBoundaryPoint b = new LexiconBoundaryPoint();
                    b.Start = b.Type = b.End = 0;
                    bool isHeading = true;
                    int type = 1;
                    for (int i = 0; i < PerfomanceFile.Text.Length; i++)
                    {
                        if (PerfomanceFile.Text[i] == '\r')
                        {
                            if (i + 1 < PerfomanceFile.Text.Length)
                            {
                                    b.End = i - 1;
                                    b.Type = type;
                                    lbp.Add(b);
                                    b = new LexiconBoundaryPoint();
                                    b.Type = b.End = 0;
                                    b.Start = i + 1;
                                    continue;
                            }
                        }
                        else if (PerfomanceFile.Text[i] == '\n')
                        {
                            // new line
                            if (isHeading)
                            {
                                b.End = i - 1;
                                b.Type = type;
                                lbp.Add(b);
                                b = new LexiconBoundaryPoint();
                                b.Start = b.Type = b.End = 0;
                                isHeading = false;
                                b.Start = i + 1;
                                b.Type = type = 2;
                                continue;
                            }
                            else
                            {
                                b.Type = type = 2;
                                b.End = i - 1;
                                lbp.Add(b);
                                b = new LexiconBoundaryPoint();
                                b.Start = b.Type = b.End = 0;
                                b.Start = i + 1;
                                continue;
                            }
                        }
                    }
                    string value;
                    int a = 0;
                    ListViewItem lv = new ListViewItem();
                    foreach (LexiconBoundaryPoint l in lbp)
                    {
                        value = PerfomanceFile.Text.Substring(l.Start, (l.End - l.Start) + 1);
                        if (l.Type == 1)
                        {
                            // heading
                            ColumnHeader c = new ColumnHeader();
                            c.Name = value;
                            c.Text = value;
                            PerformanceTable.Columns.Add(c);
                        }
                        else if (l.Type == 2)
                        {
                            // item
                            if (a == 0)
                            {
                                lv.Text = value;
                                a++;
                            }
                            else
                            {
                                if (a < PerformanceTable.Columns.Count - 1)
                                {
                                    lv.SubItems.Add(value);
                                    a++;
                                }
                                else
                                {
                                    lv.SubItems.Add(value);
                                    PerformanceTable.Items.Add(lv);
                                    lv = new ListViewItem();
                                    a = 0;
                                }
                            }
                        }
                        // else i dunno
                    }
                    PerformanceTable.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
                }
                
                #endregion
                #region LBPFile
                if (LBPFile.Text != "" && LBPFile.Text != null)
                {
                    LBPTable.Clear();
                    List<LexiconBoundaryPoint> lbp = new List<LexiconBoundaryPoint>();
                    LexiconBoundaryPoint b = new LexiconBoundaryPoint();
                    b.Start = b.Type = b.End = 0;
                    bool isHeading = true;
                    int type = 1;
                    for (int iii = 0; iii < LBPFile.Text.Length; iii++)
                    {
                        if (LBPFile.Text[iii] == '\r')
                        {
                            if (iii + 1 < LBPFile.Text.Length)
                            {
                                b.End = iii - 1;
                                b.Type = type;
                                lbp.Add(b);
                                b = new LexiconBoundaryPoint();
                                b.Type = b.End = 0;
                                b.Start = iii + 1;
                                continue;
                            }
                        }
                        else if (LBPFile.Text[iii] == '\n')
                        {
                            // new line
                            if (isHeading)
                            {
                                b.End = iii - 1;
                                b.Type = type;
                                lbp.Add(b);
                                b = new LexiconBoundaryPoint();
                                b.Start = b.Type = b.End = 0;
                                isHeading = false;
                                b.Start = iii + 1;
                                b.Type = type = 2;
                                continue;
                            }
                            else
                            {
                                b.Type = type = 2;
                                b.End = iii - 1;
                                lbp.Add(b);
                                b = new LexiconBoundaryPoint();
                                b.Start = b.Type = b.End = 0;
                                b.Start = iii + 1;
                                continue;
                            }
                        }
                    }
                    string value;
                    int a = 0;
                    ListViewItem lv = new ListViewItem();
                    foreach (LexiconBoundaryPoint l in lbp)
                    {
                        value = LBPFile.Text.Substring(l.Start, (l.End - l.Start) + 1);
                        if (l.Type == 1)
                        {
                            // heading
                            ColumnHeader c = new ColumnHeader();
                            c.Name = value;
                            c.Text = value;
                            LBPTable.Columns.Add(c);
                        }
                        else if (l.Type == 2)
                        {
                            // item
                            if (a == 0)
                            {
                                lv.Text = value;
                                a++;
                            }
                            else
                            {
                                if (a < LBPTable.Columns.Count - 1)
                                {
                                    lv.SubItems.Add(value);
                                    a++;
                                }
                                else
                                {
                                    for (int d = 0; d < lv.SubItems.Count; d++)
                                    {
                                        if (lv.SubItems[d].Text.Contains("Keyword"))
                                        {
                                            lv.ForeColor = ColorKeywords;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("Identifier"))
                                        {
                                            lv.ForeColor = ColorIdentifiers;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("Literal"))
                                        {
                                            lv.ForeColor = ColorLiterals;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("Punctuator"))
                                        {
                                            lv.ForeColor = ColorPunctuators;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("Operator"))
                                        {
                                            lv.ForeColor = ColorOperators;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("Comment"))
                                        {
                                            lv.ForeColor = ColorComments;
                                        }
                                        else if (lv.SubItems[d].Text.Contains("PreProcessorDirective"))
                                        {
                                            lv.ForeColor = ColorPreProcessorDirectives;
                                        }
                                    }
                                    lv.SubItems.Add(value);
                                    LBPTable.Items.Add(lv);
                                    lv = new ListViewItem();
                                    a = 0;
                                }
                            }
                        }
                        // else i dunno
                    }
                    LBPTable.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
                    
                }
                #endregion

            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("https://sharp.codeplex.com/");
        }
    }
}
